package com.tatesuke.automine.board;


/**
 * <p>
 * マインスイーパーの盤面です。
 * 二次元の格子で構成され、それぞれのセルは行番号、列番号で表されます。行番号、列番号はゼロから始まります。
 *
 * <pre>
 * 　列→
 * 　　０１２３４５・・・
 * 行０□□□□□□
 * ↓１□□□□□□
 * 　２□■□□□□
 * 　３□□□□□□
 * 　４□□□□□□
 * 　・
 * ■の座標：行2,列1
 * </pre>
 *
 * <p>
 * 盤面は状態を持っています。{@link BoardState}を見てください。
 * <p>
 * その他ルールはググッてください。
 *
 * @author tatesuke
 */
public interface Board {

	/**
	 * この盤面の爆弾の数が不明であることを表す定数です。
	 *
	 * @see #getBombCount();
	 */
	static final int BOMB_COUNT_UNKOWN = -1;

	/**
	 * この盤面の行数を返します。
	 *
	 * @return 行数
	 */
	int getRowSize();

	/**
	 * この盤面の列数を返します。
	 *
	 * @return 列数
	 */
	int getColumnSize();

	/**
	 * <p>
	 * この盤面に爆弾がいくつあるかを返します。 このメソッドの戻り値は、<b>残りの爆弾の個数でない</b>ことに注意して下さい。
	 * <p>
	 * 爆弾の数が不明の場合、このメソッドは定数{@link #BOMB_COUNT_UNKOWN}を返します。
	 *
	 * @return 爆弾の数、もしくは{@code BOMB_COUNT_UNKOWN}
	 */
	int getBombCount();

	/**
	 * この盤面の状態を返します。
	 *
	 * @return この盤面の状態
	 * @see BoardState
	 */
	BoardState getState();

	/**
	 * 盤面をリセットします。
	 */
	void reset();

	/**
	 * 指定されたセルの状態を返します。この盤面の範囲外の座標を指定した場合{@link CellState#SENTRY}を返します。
	 *
	 * @param row
	 *            指定セルの行
	 * @param column
	 *            指定セルの列
	 * @return 指定されたセルの種類
	 * @throws IllegalStateException
	 *             盤面が爆発状態、もしくはクリア状態の時に呼び出した場合
	 * @see CellState
	 */
	CellState getCellState(int row, int column);

	/**
	 * <p>
	 * 開いていないセルを開けます。開けた結果、爆弾が爆発した場合は爆発状態、クリアした場合はクリア状態に状態遷移します。
	 * <p>
	 * 指定されたセルが{@link CellState#CLOSE}でない場合は無視します。
	 *
	 * @param row
	 *            開くセルの行
	 * @param column
	 *            開くセルの列
	 * @throws IllegalStateException
	 *             盤面が爆発状態、もしくはクリア状態の時に呼び出した場合
	 * @throws IndexOutOfBoundsException
	 *             存在しない座標を指定された場合
	 */
	void open(int row, int column);

	/**
	 * 以下の条件に合致する時、指定セルの回りのセルを全て開けます（いわゆる同時押しの操作）。
	 * 条件に合致しないは無視するか、例外がなげられます。
	 * <ul>
	 *   <li>指定セルが開いていること
	 *   <li>指定セルの回りに、ヒントと同じ数の旗が立っている場合
	 * </ul>
	 *
	 * @param row
	 *            指定セルの行
	 * @param column
	 *            指定セルの列
	 * @throws IllegalStateException
	 *             盤面が爆発状態、もしくはクリア状態の時に呼び出した場合
	 * @throws IndexOutOfBoundsException
	 *             存在しない座標を指定された場合
	 */
	void openAllNeighbors(int row, int column);

	/**
	 * 指定されたセルの旗の上げ下げを行います。指定されたセルが開いていないなら旗を上げ、すでに旗が上がっていれば下ろします。それ以外は無視します。
	 *
	 * @param row
	 *            指定セルの行
	 * @param column
	 *            指定セルの列
	 * @throws IndexOutOfBoundsException
	 *             存在しない座標を指定された場合
	 * @throws IllegalStateException
	 *             盤面が爆発状態、もしくはクリア状態の時に呼び出した場合
	 */
	void toggleFlag(int row, int column);

	/**
	 * 指定されたセルの周りの爆弾の数を返します。このメソッドは開いているセルにしか指定できません。
	 *
	 * @param row
	 *            指定セルの行
	 * @param column
	 *            指定セルの列
	 * @throws IllegalStateException
	 *             盤面が爆発状態、もしくはクリア状態の時に呼び出した場合。もしくは開いていないマスを指定した場合。
	 * @throws IndexOutOfBoundsException
	 *             存在しない座標を指定された場合
	 */
	int getHint(int row, int column);
}
